
"""
The plugin transfers the hexadecimal data into the binrary format.

It treats all the data in hexadecimal and supports several extensions of the \
normal plain hexadecimal data:

<ul>
  <li>The plug-in works to do convert two bytes once even more characters are \
      put together</li>
  <li><code>0x</code> before the hexadecimal will be ignored. But the leading \
      <code>0</code> won't be treated as octal.</li>
  <li>All space characters including SPACE, TAB, Carriage, Return will be \
      ignored except that they're delimeters for the data.</li>
  <li>Comma (,) is also treated as the delimeter like space characters</li>
  <li>Hash (#), semicolon (;) and C++ style slash-slash (//) are considered \
      as the comment characters to comment out the comment afterwards</li>
</ul>

With the explanation above, a tricky expression need highlight is:

<code>01 234 5 67</code> will be treated as <code>01 23 04 05 67</code> and \
converted into the binaries.
"""

__version__ = '1.3.2'

__aof__ = ('Hexadecimal Converter', 'HEX')
__extension__ = (
    ('Hex Files', ('*.hex',)),
    ('Text Files', ('*.conf', '*.txt'))
)


def _si(value):
    try:
        return int(value, 16)
    except ValueError:
        return -1


class _ExtendedHexDecoder:
    def Execute(self, source, output, notify, **kws):
        ret = False

        start = kws.get('start', 0)
        size = length = kws.get('length', len(source)) - start
        if length < 0:
            length = 0

        source.seek(start)
        while length > 0:
            li, ret, slash, comment = ('', True, False, False)
            while length > 0 and ret:
                c = source.read(1)
                length -= 1
                if c == '\r' or c == '\n':
                    comment = False
                    break
                elif comment:
                    continue

                if c == '/':
                    if not slash:
                        slash = True
                    else:
                        slash = False
                        comment = True

                    continue

                if slash:
                    ret = False
                if c == '#' or c == ';':
                    comment = True
                elif c == ' ' or c == '\t' or c == ',':
                    # ignore blank characters and do parse as a delimeter
                    break
                elif (c == 'x' or c == 'X') and len(li) > 0 and li[-1] == '0':
                    # handle the prefix 0x
                    li = li[:-1]
                elif c in '0123456789ABCDEFabcdef':
                    li += c
                else:
                    ret = False

            if not ret:
                break
            if int(10 * length / size) == 10 * length / size:
                notify(100 * (size - length) / size,
                       'Parse Hex data ...')

            for k in xrange(0, len(li), 2):
                o = _si(li[k:k + 2])
                output.write(chr(o))

        return ret


def cvtService():
    return _ExtendedHexDecoder
